"""
Technique for Order Preference by Similarity to an Ideal Solution(TOPSIS)
"""

import numpy as np
import pandas as pd
import re
from sklearn.preprocessing import MinMaxScaler, StandardScaler, normalize

np.set_printoptions(suppress=True, precision=4)

# Step1: 加载原始数据
data = np.loadtxt('data/yjs.txt', delimiter='\s+', dtype=str)
data = np.array([re.split('\s+', item) for item in data]).astype(np.float)
data_original = np.copy(data)
# Step2: 原始矩阵正向化


def interval_val_scalar(x, lintrvl, rintrvl, lb, ub):
    """
        区间型属性的变换
        设最优属性区间给定为[lintrvl, rintrvl]
        lb: 无法容忍下限
        ub: 无法容忍上限
    """
    scale_results = []
    for item in x:
        if lb <= item <= lintrvl:
            res = 1 - (lintrvl - item) / (lintrvl - lb)
        elif lintrvl < item <= rintrvl:
            res = 1
        elif rintrvl < item <= ub:
            res = 1 - (item - rintrvl) / (ub - rintrvl)
        else:
            res = 0
        scale_results.append(res)
    return scale_results


# 对属性“生师比”的数据进行最优值为给定区间的变换
data[:, 1] = interval_val_scalar(data[:, 1], lintrvl=5, rintrvl=6, lb=2, ub=12)

# Step3: 正向矩阵标准化
data = normalize(data, norm='l2', axis=0)  # 向量规范化

# Step4: 计算得分并归一化
data *= [0.2, 0.3, 0.4, 0.1]  # 加权规范阵
pos_ideal_sol = np.append(
    np.max(data[:, [0, 1, 2]], axis=0), data[:, 3].min())  # 正理想解
neg_ideal_sol = np.append(
    np.min(data[:, [0, 1, 2]], axis=0), data[:, 3].max())  # 负理想解

dist_pos, dist_neg = np.array([]), np.array([])
for i in range(data.shape[0]):  # 计算各方案到理想解的距离
    dist_pos = np.append(dist_pos, np.linalg.norm(data[i, :] - pos_ideal_sol))
    dist_neg = np.append(dist_neg, np.linalg.norm(data[i, :] - neg_ideal_sol))

score = dist_neg / (dist_neg + dist_pos) # 计算排序指标值
score /= np.sum(score) # 归一化
data = np.insert(data_original, 4, values=score, axis=1)
result = pd.DataFrame(data, index=range(1, 6), columns=['人均专著', '生师比', '科研经费', '逾期毕业率', '综合得分指数'])
print(result)
